/**
 * @Author       : Hejh(3010733382@qq.com)
 * @Version      : V1.0
 * @Date         : 2024-01-14 17:38:59
 * @Description  : 角色接口的验证中间件
 */
const Joi = require('joi')
const { Op } = require('sequelize')
const R = require('@/models/Response')
const {
  Role,
  Permission,
  User,
  UserDepartment,
  SystemOption,
  SourceAuth
} = require('@/models/model')
const { ERROR_USER_CODE, ERROR_SYSTEM_CODE } = require('@/constants/errorCode')
const { IS_INTEGER, IS_UNSAFE_INTEGER } = require('@/constants/joiSchema')

const roleSchema = {
  roleIds: Joi.array().items(IS_UNSAFE_INTEGER),
  roleId: IS_UNSAFE_INTEGER,
  page: IS_INTEGER.min(1).default(1),
  pageSize: IS_INTEGER.min(1).default(999),
  name: Joi.string().min(1).max(50),
  type: IS_INTEGER.valid(0, 1),
  isVisible: IS_INTEGER.valid(0, 1),
  desc: Joi.string().allow('', null),
  label: Joi.string(),
  permissionIds: Joi.array().items(IS_UNSAFE_INTEGER)
}

const dumpCheck = {
  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证角色ID的合法性
   * @param {array<string>} roleIds 角色ID数组
   */
  checkRoleIds: async (roleIds, ingoreSystem = false) => {
    let newroleIds = [...new Set(roleIds)]
    // 不能出现重复的
    if (newroleIds.length !== roleIds.length) {
      return false
    }

    newroleIds = newroleIds.map((item) => BigInt(item))

    if (newroleIds.length === 0) {
      return true
    }

    // 查看不重复的和数据库的是否对的上
    const myWhere = {
      id: {
        [Op.in]: newroleIds
      }
    }
    if (!ingoreSystem) {
      myWhere.system = 0
    }
    const roles = await Role.findAll({
      where: myWhere
    })
    if (roles.length !== newroleIds.length) {
      return false
    }

    return true
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证角色名称是否重复
   * @param {string} roleName 角色名称
   */
  checkRoleName: async (roleName) => {
    const role = await Role.findOne({
      where: {
        name: roleName
      }
    })
    if (role) {
      return false
    }
    return true
  },

  /**
   * @author: Hejh(3010733382@qq.com)
   * @description: 验证权限ID是否正确
   * @param {array<string>} permissionIds 权限ID数组
   */
  checkPermissionIds: async (permissionIds) => {
    let newPermissionIds = [...new Set(permissionIds)]
    // 不能出现重复的
    if (newPermissionIds.length !== permissionIds.length) {
      return false
    }

    newPermissionIds = newPermissionIds.map((item) => BigInt(item))

    if (newPermissionIds.length === 0) {
      return true
    }

    // 查看不重复的和数据库的是否对的上
    const permissions = await Permission.findAll({
      where: {
        id: {
          [Op.in]: newPermissionIds
        }
      }
    })
    if (permissions.length !== newPermissionIds.length) {
      return false
    }

    return true
  }
}

/**
 * @description 角色列表查询的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.listRoleValidate = async (ctx, next) => {
  const schema = Joi.object({
    page: roleSchema.page,
    pageSize: roleSchema.pageSize,
    name: roleSchema.name,
    type: roleSchema.type,
    isVisible: roleSchema.isVisible
  }).validate(ctx.query)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }
  ctx.query = schema.value
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 创建和更新角色时的验证
 * @param {*} ctx koa上下文
 * @param {*} roleId 角色ID
 * @param {*} roleName 角色名称
 * @param {array<string>} permissionIds 权限ID数组
 */
const addAndUpdCheck = async (ctx, roleId, roleName, permissionIds) => {
  // 验证roleId的合法性
  if (roleId !== null) {
    const b4 = await dumpCheck.checkRoleIds([roleId], true)
    if (!b4) {
      ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
      return false
    }
  }

  // 验证角色名称的合法性
  if (roleName !== null && !roleId) {
    const b3 = await dumpCheck.checkRoleName(roleName)
    if (!b3) {
      ctx.body = R.error(ERROR_USER_CODE.ROLE_NAME_ERROR)
      return false
    }
  }

  // 验证权限ID数组的合法性
  if (permissionIds !== null) {
    const b5 = await dumpCheck.checkPermissionIds(permissionIds)
    if (!b5) {
      ctx.body = R.error(ERROR_USER_CODE.PERMISSION_ID_ERROR)
      return false
    }
  }

  return true
}

/**
 * @description 创建角色时的参数验证
 * @param {*} ctx
 * @param {*} next
 * @returns
 */
module.exports.createRoleValidate = async (ctx, next) => {
  const schema = Joi.object({
    name: roleSchema.name.required(),
    desc: roleSchema.desc,
    type: roleSchema.type.required(),
    label: roleSchema.label.required(),
    isVisible: roleSchema.isVisible.required(),
    permissionIds: roleSchema.permissionIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { name, permissionIds } = ctx.request.body

  // 验证角色名称的合法性
  const b = await addAndUpdCheck(ctx, null, name, permissionIds)
  if (!b) {
    return
  }
  // 到这里说明参数没有问题,协作角色情况[0],[-1],[xxx,xxx]
  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 更新角色时的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.updateRoleValidate = async (ctx, next) => {
  const schema = Joi.object({
    roleId: roleSchema.roleId.required(),
    name: roleSchema.name.required(),
    desc: roleSchema.desc,
    // type: roleSchema.type.required(),
    label: roleSchema.label.required(),
    isVisible: roleSchema.isVisible.required(),
    permissionIds: roleSchema.permissionIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { roleId, name, permissionIds } = ctx.request.body

  const b = await addAndUpdCheck(ctx, roleId, name, permissionIds)
  if (!b) {
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 批量删除角色接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.delRolesValidate = async (ctx, next) => {
  const schema = Joi.object({
    roleIds: roleSchema.roleIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { roleIds } = ctx.request.body

  // 验证角色ID数组的合法性
  const b4 = await dumpCheck.checkRoleIds(roleIds)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  const newRoleIds = roleIds.map((v) => BigInt(v))
  // 看角色是否被引用中，系统角色-user，文档角色-user-department
  const b5 = await User.findOne({
    where: {
      roleId: {
        [Op.in]: newRoleIds
      }
    }
  })
  if (b5) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_USER_ERROR)
    return
  }

  const b6 = await UserDepartment.findOne({
    where: {
      roleId: {
        [Op.in]: newRoleIds
      }
    }
  })

  if (b6) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_USER_ERROR)
    return
  }

  // 看系统配置的新用户默认加入部门中是否存在该角色
  const aOption = await SystemOption.findOne({
    where: {
      key: 'defaultDepInfo'
    }
  })

  // console.log(aOption)

  const depsInfo = JSON.parse(aOption.value)

  if (depsInfo.some((item) => roleIds.includes(item.authRole))) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_USER_ERROR)
    return
  }

  // source-auth权限
  const sourceAuth = await SourceAuth.findOne({
    where: {
      roleId: {
        [Op.in]: newRoleIds
      }
    }
  })

  if (sourceAuth) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_USER_ERROR)
    return
  }

  await next()
}

/**
 * @author: Hejh(3010733382@qq.com)
 * @description: 角色排序接口的参数验证
 * @param {*} ctx
 * @param {*} next
 */
module.exports.sortRolesValidate = async (ctx, next) => {
  const schema = Joi.object({
    roleIds: roleSchema.roleIds.required()
  }).validate(ctx.request.body)

  if (schema.error) {
    ctx.body = R.error(ERROR_SYSTEM_CODE.PARAMS_SCHEMA_ERROR)
    return
  }

  const { roleIds } = ctx.request.body

  // 验证角色ID数组的合法性
  const b4 = await dumpCheck.checkRoleIds(roleIds, true)
  if (!b4) {
    ctx.body = R.error(ERROR_USER_CODE.ROLE_ID_ERROR)
    return
  }

  await next()
}
